﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.ActiveRecord;
using System.Collections;
using System.Web;
using System.Configuration;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.PanGu;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.QueryParsers;
using Windvoice.Library;
using PanGu;
using System.IO;

namespace Windvoice.Blog
{
    public partial class Article : ActiveRecordBase<Article>
    {
        private static string IndexPath
        {
            get
            {
                if (HttpContext.Current != null)
                    return HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["IndexPath"]);
                else
                    return String.Empty;
            }
        }
        //private static string IndexPath = "";
        private static Analyzer WordAnalyzer = new PanGuAnalyzer();

        public static Article Get(string uniqueKey)
        {
            var query = from a in FindAll() where a.UniqueKey == uniqueKey select a;
            return query.Count() == 1 ? FindAll().Where(a => a.UniqueKey == uniqueKey).Single() : null;
        }

        public static Article[] GetList(int pageIndex, int pageSize, int categoryID, out int recordCount)
        {
            recordCount = categoryID == 0 ? FindAll().Count() : FindAll().Where(a => a.CategoryID == categoryID).Count();
            int PageLowerBound = (pageIndex - 1) * pageSize;

            if (categoryID == 0) 
                return FindAll().OrderByDescending(a=>a.ID).Skip(PageLowerBound).Take(pageSize).ToArray();
            else 
                return FindAll().Where(a => a.CategoryID == categoryID).OrderByDescending(a => a.ID).Skip(PageLowerBound).Take(pageSize).ToArray();
        }

        public static int GetArticleCount(int categoryID)
        {
            if (categoryID == 0)
                return Article.FindAll().Length;
            else
                return (from a in Article.FindAll() where a.CategoryID == categoryID select a).Count();
        }

        public static void HitPlus(int articleID)
        {
            var article = Find(articleID);
            article.Hits += 1;
            article.Update();
        }
        
        public static Article[] Search(string word)
        {
            IndexSearcher searcher = new IndexSearcher(IndexPath);
            QueryParser parser = new QueryParser("Title", WordAnalyzer);

            Segment segment = new Segment();
            List<WordInfo> words = segment.DoSegment(word).Where(w=>w.ToString().Length>1).ToList();

            var query = new BooleanQuery();
            foreach (var SegmentedWord in words)
                query.Add(new MultiFieldQueryParser(new string[] { "UniqueKey", "Title", "Content" }, WordAnalyzer).Parse(SegmentedWord.ToString()), BooleanClause.Occur.SHOULD);
            
            //var query = new MultiFieldQueryParser(new string[] { "UniqueKey", "Title", "Content" }, WordAnalyzer).Parse(word);
            //query.Add(new FuzzyQuery(new Term("UniqueKey", word)), BooleanClause.Occur.SHOULD);
            //query.Add(new FuzzyQuery(new Term("Title", word)), BooleanClause.Occur.SHOULD);
            //query.Add(new FuzzyQuery(new Term("Content", word)), BooleanClause.Occur.SHOULD);

            Hits hits = searcher.Search(query);
            var ArticleIdentities = new ArrayList();
            for (int i = 0; i < hits.Length(); i++)
                ArticleIdentities.Add(Convert.ToInt32(hits.Doc(i).GetField("ID").StringValue()));

            return FindAll().Where(a => ((int[])ArticleIdentities.ToArray(typeof(int))).Contains(a.ID)).Take(5).ToArray();
        }

        public static void CreateIndex(bool isForceRebuild=true)
        {
            //if force rebuild, do not check if index exists, just create it
            //if not force rebuild, check if index exists, if index exists, do not rebuild
            if (!isForceRebuild && new DirectoryInfo(IndexPath).GetFiles().Length > 0)
                return;

            IndexWriter writer = new IndexWriter(IndexPath, WordAnalyzer, true);

            foreach (var article in FindAll())
            {
                Document doc = new Document();

                doc.Add(new Field("ID", Convert.ToString(article.ID), Field.Store.YES, Field.Index.UN_TOKENIZED));
                doc.Add(new Field("UniqueKey", Convert.ToString(article.UniqueKey), Field.Store.YES, Field.Index.TOKENIZED));
                doc.Add(new Field("Title", Convert.ToString(article.Title), Field.Store.YES, Field.Index.TOKENIZED));
                doc.Add(new Field("Content", Convert.ToString(article.Content), Field.Store.YES, Field.Index.TOKENIZED));

                writer.AddDocument(doc);
            }

            writer.Commit();
            writer.Optimize();
            writer.Close();
        }

        public void AppendIndex()
        {
            IndexWriter writer = new IndexWriter(IndexPath, WordAnalyzer,false);

            Document doc = new Document();

            doc.Add(new Field("ID", Convert.ToString(this.ID), Field.Store.YES, Field.Index.UN_TOKENIZED));
            doc.Add(new Field("UniqueKey", Convert.ToString(this.UniqueKey), Field.Store.YES, Field.Index.TOKENIZED));
            doc.Add(new Field("Title", Convert.ToString(this.Title), Field.Store.YES, Field.Index.TOKENIZED));
            doc.Add(new Field("Content", Convert.ToString(this.Content), Field.Store.YES, Field.Index.TOKENIZED));

            writer.AddDocument(doc);
            writer.Optimize();
            writer.Commit();
            writer.Close();
        }
        
        public Article[] GetNeighbours()
        {
            var ArticleList = FindAll().OrderByDescending(a=>a.ID).ToList();
            var Index = 0;
            for (int i = 0; i < ArticleList.Count; i++)
            {
                if (ArticleList[i].ID == this.ID)
                {
                    Index = i;
                    break;
                }
            }

            Article[] Neighbours = new Article[2];
            Neighbours[0] = Index <= 0 ? null : ArticleList[Index - 1];
            Neighbours[1] = Index >= ArticleList.Count-1 ? null : ArticleList[Index + 1];

            return Neighbours;
        }

        public static Article[] GetHotArticles(int topCount)
        {
            return FindAll().OrderByDescending(a => a.Hits).Take(topCount).ToArray();
        }

        public static Article[] GetRandomArticles(int topCount)
        {
            int MaxIndex = FindAll().Count();

            if (MaxIndex <= topCount)
                topCount = MaxIndex;
                //return FindAll().ToArray();

            Article[] Articles = FindAll().ToArray();
            ArrayList RandomArray = EnumHelper.GetIntArray(start: 0, end: topCount);

            List<Article> ArticleList = new List<Article>();
            int i = 0;
            while (i < topCount)
            {
                Random rand = new Random(DateTime.Now.Millisecond);
                var NextRandom = rand.Next(0, RandomArray.Count);
                var SafeRandom = Convert.ToInt32(RandomArray[NextRandom]);

                ArticleList.Add(Articles[SafeRandom]);
                RandomArray.RemoveAt(NextRandom);
                i++;
            }

            return ArticleList.ToArray();
        }
    }
}